import React from "react";
import {Button, Row, Col} from 'antd';
import {messages, deepCopy} from "share/common";
import GridItem from 'components/template/dragger/grid-item'
import SlideFrame from 'components/slide-frame'

import 'styles/components/template/dragger/dragger.scss'
import {initLayout, getFirstCollison} from 'components/template/dragger/layout'

class Dragger extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      tempNode: {
        order: 0,
        width: 0,
        height: 0
      },
      col: 0,
      isMoving: false,
      layout: [],
      moduleSetShow: false
    }
  }

  componentWillMount() {
    this.setState({
      layout: initLayout(this.props.layout, this.props.col),
      children: this.props.children,
      col: this.props.col
    });
  }

  componentDidMount() {
    let date = new Date();
    date.setDate(date.getDate() -1);
    date.toUTCString();
    document.cookie = `hly-layout=;expires=${date};path=/`;
  }

  componentWillReceiveProps(nextProps) {
    this.setState({
      layout: initLayout(nextProps.layout, nextProps.col),
      moduleSetShow: nextProps.show
    });
    this.toggleUserSelect(nextProps.isOperating ? "none" : "auto");
  }

  shouldComponentUpdate(nextProps, nextState) {
    const { storageKey } = this.props;
    storageKey && localStorage.setItem(storageKey, JSON.stringify(nextState.layout));
    return true;
  }

  /**移动预览方块的位置，只允许与其他模块交换位置*/
  onDrag = (offsetX, offsetY, dom, key) => {
    const {layout, tempNode, startNode, col} = this.state;
    let layoutTemp = deepCopy(layout);
    let layoutItem = layoutTemp.filter(item => item.key === key);
    let thisDom = {
      offsetTop: offsetY,
      offsetLeft: offsetX,
      w: dom.clientWidth,
      h: dom.clientHeight
    };

    /** 判断是否有碰撞盒子，碰撞并边界超过盒子宽度的一半，交换位置*/
    let collisonLayout = getFirstCollison(layoutTemp, layoutItem, thisDom, col);
    if (collisonLayout) {
      /*                                  ↓
               1          2              3          4
            --------------------------------------------
       set  | [1,1]  [1,1],[2,2]  [1,1],[2,2]   [1,1],[2,2]
        0   | [0,0]  [0,0]        [0,0]         [0,0]
        1     [1,0]  [1,1]        [1,2]         [1,1]
        2     [2,2]  [2,0]        [2,2]
      temp    [1]    [2]          [1]
      */
      /** 连续交换时被越过的盒子恢复原order值  如果最终目标和初始目标相同  恢复dragStart时的布局 若不同 交换order*/
      if (collisonLayout.order === startNode) {
        this.setState({
          layout: initLayout(this.state.layoutS, col),
          tempNode: {
            order: startNode,
            width: tempNode.width,
            height: tempNode.height
          },
        })
      } else {
        layoutTemp.map(item => {
          if (item.key === collisonLayout.key) {
            item.order = startNode;
          } else {
            this.state.layoutS.map(items => {
              if (items.key === item.key) {
                item.order = items.order;
              }
            })
          }
        });
        this.setState({
          layout: initLayout(layoutTemp, col),
          tempNode: {
            order: collisonLayout.order,
            width: tempNode.width,
            height: tempNode.height
          },
        })
      }
    }
  };

  onDragStart = (order, wPx, hPx) => {
    this.setState({
      startNode: order,
      tempNode: {
        order: order,
        width: wPx,
        height: hPx
      },
      layoutS: this.state.layout,
      isMoving: true
    })
  };

  onDragEnd = (key) => {
    const {layout, tempNode, col} = this.state;
    let layoutTemp = layout.map(item => {
      item.key === key && (item.order = tempNode.order);
      return item;
    });

    this.setState({
      isMoving: false,
      layout: initLayout(layoutTemp, col)
    }, () => {
      this.props.refresh(initLayout(layoutTemp, col));
    })
  };

  onResizeX = (offsetX, colW, layoutItem, lastY) => {
    const {margin, rowHeight, col} = this.props;
    let offGridX = Math.ceil(offsetX / (colW + margin[1]));
    let newW = Math.min(Math.max(layoutItem.w + offGridX, 1), col);
    this.setState({
      newW: newW,
      tempNode: {
        order: layoutItem.order,
        width: newW * colW + (newW - 1) * margin[1],
        height: lastY
      }
    })
  };

  onResizeY = (offsetY, colW, layoutItem, lastX) => {
    const {margin, rowHeight, draggableHeight} = this.props;
    let offGridY = Math.ceil(offsetY / (rowHeight + margin[0]));
    let newH = Math.max(layoutItem.h + offGridY, 1);
    this.setState({
      newH: newH,
      tempNode: {
        order: layoutItem.order,
        width: lastX,
        height: Math.max(newH * rowHeight + (newH - 1) * margin[0], rowHeight, draggableHeight),
      }
    })
  };

  onResizeF = (offsetX, colW, layoutItem, percent) => {
    const {margin, rowHeight, col} = this.props;
    let offGridX = Math.ceil(offsetX / (colW + margin[1]));
    let newW = layoutItem.GridX + layoutItem.w === col ? layoutItem.w : Math.max(layoutItem.w + offGridX, 1);
    let newH = Math.ceil((newW * colW + (newW - 1) * margin[1]) * percent / (rowHeight + margin[0]));
    this.setState({
      newW: newW,
      newH: newH,
      tempNode: {
        order: layoutItem.order,
        width: newW * colW + (newW - 1) * margin[1],
        height: newH * rowHeight + (newH - 1) * margin[0],
      }
    });
  };

  onResizeStart = (key, colW) => {
    const {layout} = this.state;
    const {margin, rowHeight} = this.props;
    let order = 0, w = 0, h = 0;
    layout.map(item => {
      if (item.key === key) {
        order = item.order;
        w = item.w;
        h = item.h;
      }
    });
    this.setState({
      newW: w,
      newH: h,
      isMoving: true,
      tempNode: {
        order: order,
        width: w * colW + (w - 1) * margin[1],
        height: h * rowHeight + (h - 1) * margin[0]
      }
    })
  };

  onResizeEnd = (key) => {
    const {layout, newW, newH, col} = this.state;
    let row = 0;
    let layoutTemp = initLayout(layout, col).map(item => {
      if (item.key === key) {
        item.w = newW;
        item.h = newH;
        row = item.GridY;
      }
      return item;
    });
    layoutTemp.map(item => {
      if (row === item.GridY) {
        !item.firm && (item.h = newH);
      }
    });
    this.setState({
      layout: initLayout(layoutTemp, col),
      isMoving: false
    }, () => {
      this.props.refresh(initLayout(layoutTemp, col));
    })
  };

  toggleBox = (layout) => {
    this.props.toggleSlideFrame(false);
    layout && this.props.refresh(initLayout(layout, this.state.col));
  };

  toggleUserSelect = (value) => {
    document.body.style.userSelect = value;
    document.body.style.webkitUserSelect = value;
    document.body.style.msUserSelect = value;
    document.body.style.MozUserSelect = value;
  };

  getGridItem = (child, index) => {
    const {layout} = this.state;
    const {containerWidth, col, rowHeight, margin, padding, draggableHeight, isOperating, draggingStyle} = this.props;
    return (
      layout[index] && layout[index].show &&
      <GridItem layout={layout[index]}
                margin={margin}
                col={col}
                draggingStyle={draggingStyle}
                containerWidth={containerWidth}
                containerPadding={padding}
                rowHeight={rowHeight}
                draggableHeight={draggableHeight}
                isOperating={isOperating}
                onDrag={(offsetX, offsetY, colW, key) => this.onDrag(offsetX, offsetY, colW, key)}
                onDragStart={(order, wPx, hPx) => this.onDragStart(order, wPx, hPx)}
                onDragEnd={(key) => this.onDragEnd(key)}
                onResizeX={(offsetX, colW, layoutItem, lastY) => this.onResizeX(offsetX, colW, layoutItem, lastY)}
                onResizeY={(offsetX, colW, layoutItem, lastX) => this.onResizeY(offsetX, colW, layoutItem, lastX)}
                onResizeF={(offsetX, colW, layoutItem, percent) => this.onResizeF(offsetX, colW, layoutItem, percent)}
                onResizeStart={(key, colW) => this.onResizeStart(key, colW)}
                onResizeEnd={(key) => this.onResizeEnd(key)}>
        {(newProps) => React.cloneElement(child, {...newProps})}
      </GridItem>
    )
  };

  render() {
    const {containerWidth, padding, margin, className, style, toggleSlideFrame, children} = this.props;
    const {isMoving, moduleSetShow, layout, tempNode} = this.state;
    const flexOrder = {
      WebkitBoxOrdinalGroup: tempNode.order,
      MozBoxOrdinalGroup: tempNode.order,
      MsFlexOrder: tempNode.order,
      WebkitOrder: tempNode.order
    };
    return (
      <div className="dragger">
        <div className={`dragger-layout ${className}`}
             ref="draggerLayout"
             style={{
               ...style,
               width: containerWidth,
               padding: `${padding[0]}px ${padding[1]}px`,
               marginLeft: margin[1]/2
             }}>
          <div style={{
            position: "absolute",
            zIndex: 2,
            opacity: 0,
            width: containerWidth,
            height: "100%",
            display: isMoving ? "block" : "none"
          }} />
          <div id="tempNode" style={{
            ...tempNode,
            ...flexOrder,
            margin: `0 ${margin[1]}px ${margin[0]}px 0`,
            display: isMoving ? "block" : "none"
          }} />
          {containerWidth && React.Children.map(children, (item, index) => item && this.getGridItem(item, index))}
        </div>
        <SlideFrame title={messages('components.key749')/*模块设置*/}
                    show={moduleSetShow}
                    content={Slide}
                    onClose={() => toggleSlideFrame(false)}
                    afterClose={this.toggleBox}
                    params={{ layout }}/>
      </div>
    );
  }
}

class Slide extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      layout: []
    }
  }

  componentWillMount() {
    this.setState({
      layout: this.props.params.layout,
    });
  }

  componentWillReceiveProps(nextProps) {
    this.setState({ layout: nextProps.params.layout });
  }

  toggleBox = (key, show) => {
    const {layout} = this.state;
    let layoutTemp = deepCopy(layout);
    layoutTemp.map(item => {
      if (item.key === key) {
        item.show = !show;
      }
      return item
    });
    this.setState({layout: layoutTemp})
  };

  render() {
    const {layout} = this.state;
    let slideContent = [];
    layout.map((item, index) => {
      layout[index].removable && slideContent.push(<Col span={8} key={index}>
        <div className={`module-list ${item.show ? "show-item" : "hide-item"}`}
             onClick={() => this.toggleBox(item.key, item.show)}>
          {item.name}
        </div>
      </Col>);
    });
    return <div className="dragger-slide">
      <Row gutter={16}>
        {slideContent}
      </Row>
      <div className="slide-footer">
        <Button type="primary" onClick={() => this.props.close(layout)}>{messages("common.save")}</Button>
        <Button onClick={() => this.props.close()}>{messages("common.cancel")}</Button>
      </div>
    </div>
  }
}

/**
 * layout 初始默认布局
 * const layout: [
 { w: 8, h: h, key: '0', order: 0, firm: true},
 { w: 8, h: h, key: '1', order: 1 },
 { w: 8, h: h, key: '2', order: 2 },
 { w: 16, h: 14, key: '3', order: 3 },
 ]
 w: number //必填，挂件布局中宽度，栅格宽度的倍数，整数
 h: number //必填，挂件布局中高度，行高的倍数，整数
 key: number | string //必填，挂件在布局中的唯一id
 order: number //必填，flex布局排序属性
 firm: bool //非必填，为true则只能按比例resize
 */
Dragger.propTypes = {
  layout: React.PropTypes.array.isRequired,
  containerWidth: React.PropTypes.number.isRequired, // 容器宽度
  col: React.PropTypes.number.isRequired, //栅格，于是容器内元素的最小宽度就等于 width/col
  rowHeight: React.PropTypes.number.isRequired, //行高，于是容器内元素的最小高度就等于 rowHeight
  margin: React.PropTypes.array.isRequired, //元素间隙，每个元素的margin [marginBottom, marginRight]
  padding: React.PropTypes.array, //容器的padding [上下padding，左右padding]
  className: React.PropTypes.string, //容器的类名
  draggableHeight: React.PropTypes.number,
  style: React.PropTypes.object,
  draggingStyle: React.PropTypes.object,//拖动时每个元素的样式
  refresh: React.PropTypes.func,
  toggleSlideFrame: React.PropTypes.func,
  isOperating: React.PropTypes.bool,
  show: React.PropTypes.bool,
  storageKey: React.PropTypes.string //存储在本地的localStorage key名
};
Dragger.defaultProps = {
  containerWidth: 1120,
  col: 24,
  rowHeight: 32,
  margin: [10, 10],
  padding: [0, 0],
  className: '',
  draggableHeight: 36,
  layout: [],
  style: {},
  draggingStyle: {}
};

export default Dragger;
